#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <assert.h>

static int evtdev = -1;
static int fbdev = -1;
static int screen_w = 0, screen_h = 0;
static uint64_t start_tick = 0;
int open(const char *path, int flags, ...);
uint32_t NDL_GetTicks() {
  struct timeval time;
  gettimeofday(&time,NULL);
  return time.tv_sec*1000+time.tv_usec/1000-start_tick;
}

int NDL_PollEvent(char *buf, int len) {
  int fd = open("/dev/events",0);
  assert(fd != -1);
  len = read(fd,buf,len);
  return len;
}

struct DispInfo
{
  int w;
  int h;
} dispinfo;
void update_dispinfo(){
  int fd = open("/proc/dispinfo",0);
  char info[64] = {0};//"WIDTH : %d\nHEIGHT:%d\n"
  size_t len = read(fd,info,sizeof(info));
  close(fd);
  int w=0,h=0;
  int ret = sscanf(info,"WIDTH : %d\nHEIGHT:%d\n",&w,&h);
  // printf("dispinfo: w:%d h:%d ret:%d\n",w,h,ret);
  if(ret != 2) return;
  dispinfo.w = w;
  dispinfo.h = h;
}

void NDL_OpenCanvas(int *w, int *h) {
  if(*w == 0 && *h == 0) {
    update_dispinfo();
    screen_w = dispinfo.w; screen_h = dispinfo.h;
    *w = dispinfo.w; *h = dispinfo.h;
  } else {
    screen_w = *w; screen_h = *h;
  }
  return;
  if (getenv("NWM_APP")) {
    int fbctl = 4;
    fbdev = 5;
    screen_w = *w; screen_h = *h;
    char buf[64];
    int len = sprintf(buf, "%d %d", screen_w, screen_h);
    // let NWM resize the window and create the frame buffer
    write(fbctl, buf, len);
    while (1) {
      // 3 = evtdev
      int nread = read(3, buf, sizeof(buf) - 1);
      if (nread <= 0) continue;
      buf[nread] = '\0';
      if (strcmp(buf, "mmap ok") == 0) break;
    }
    close(fbctl);
  }
}


struct _FB_RECT
{
  uint32_t *pixels;int x;int y; int w; int h;
};
#define screen_x (dispinfo.w-screen_w)/2
#define screen_y (dispinfo.h-screen_h)/2

void NDL_DrawRect(uint32_t *pixels, int x, int y, int w, int h) {
  update_dispinfo();
  x += screen_x;
  y += screen_y;
  struct _FB_RECT rect = {pixels,x,y,w,h};
  int fd = open("/dev/fb",0);
  lseek(fd,0,SEEK_SET);
  assert(fd != -1);
  size_t offset = (x+y*dispinfo.w)*4;
  size_t screen_line = dispinfo.w*4;
  for (int i = 0; i < h; i++)
  {
    lseek(fd,offset,SEEK_SET);
    write(fd,pixels,w*4);
    pixels += w;
    offset += screen_line;
  }
  return;

}


void NDL_FillRect(uint32_t color, int x, int y, int w, int h) {
  update_dispinfo();
  x += screen_x;
  y += screen_y;
  int fd = open("/dev/fb",0);
  lseek(fd,0,SEEK_SET);
  assert(fd != -1);
  size_t offset = (x+y*dispinfo.w)*4;
  size_t screen_line = dispinfo.w*4;
  for (int i = 0; i < h; i++)
  {
    lseek(fd,offset,SEEK_SET);
    write(fd,&color,w*4);
    offset += screen_line;
  }
  return;
}


void NDL_OpenAudio(int freq, int channels, int samples) {
}

void NDL_CloseAudio() {
}

int NDL_PlayAudio(void *buf, int len) {
  return 0;
}

int NDL_QueryAudio() {
  return 0;
}

int NDL_Init(uint32_t flags) {
  if (getenv("NWM_APP")) {
    evtdev = 3;
  }
  start_tick = 0;
  start_tick = NDL_GetTicks();
  return 0;
}

void NDL_Quit() {
}
